//
//  NSArray+ZXAvoidCrash.m
//  MerchantBusinessClient
//
//  Created by simon on 2020/8/31.
//  Copyright © 2020 com.Chs. All rights reserved.
//  NSArray的类有4种：__NSPlaceholderArray：C初始化数组；__NSArray0：空数组；__NSSingleObjectArrayI：一个元素；__NSArrayI：多个元素；

#import "NSArray+ZXAvoidCrash.h"
#import "ZXAvoidCrashRuntime.h"
#import "ZXAvoidCrashReport.h"

@implementation NSArray (ZXAvoidCrash)

+ (void)zx_avoidCrashExchangeMethod{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        //NSArray和NSMutableArray的占位对象，instance method 和 类方法同一个;alloc创建的对象,或部分创建方法崩溃前。
        Class __NSPlaceholderArray = NSClassFromString(@"__NSPlaceholderArray");
        
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:__NSPlaceholderArray originalSelector:@selector(initWithObjects:count:) swizzledSelector:@selector(zx_avoidCrashInitWithObjects:count:)];

        ///初始化的空数组对象，包括
        /// -init，
        /// + (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
        /// + (instancetype)arrayWithArray:(NSArray<ObjectType> *)array;
        /// + (instancetype)array;
        Class __NSArray0 = NSClassFromString(@"__NSArray0");
        Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI");
        Class __NSArrayI = NSClassFromString(@"__NSArrayI");
        //类名
        Class NSArray = NSClassFromString(@"NSArray");

        
        
        ///objectAtIndex:
        
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:__NSArray0 originalSelector:@selector(objectAtIndex:) swizzledSelector:@selector(zx___NSArray0AvoidCrashObjectAtIndex:)];
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:__NSSingleObjectArrayI originalSelector:@selector(objectAtIndex:) swizzledSelector:@selector(zx___NSSingleObjectArrayIAvoidCrashObjectAtIndex:)];
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:__NSArrayI originalSelector:@selector(objectAtIndex:) swizzledSelector:@selector(zx___NSArrayIAvoidCrashObjectAtIndex:)];
        
        //objectAtIndexedSubscript:
        
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:__NSArrayI originalSelector:@selector(objectAtIndexedSubscript:) swizzledSelector:@selector(zx___NSArrayIAvoidCrashObjectAtIndexedSubscript:)];
        

        //[NSArray objectsAtIndexes:]:
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:NSArray  originalSelector:@selector(objectsAtIndexes:) swizzledSelector:@selector(zx_avoidCrashObjectsAtIndexes:)];
        
        
        //indexOfObject:inRange:
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:NSArray  originalSelector:@selector(indexOfObject:inRange:) swizzledSelector:@selector(zx_avoidCrashIndexOfObject:inRange:)];
        
        //indexOfObjectIdenticalTo:(ObjectType)anObject inRange:(NSRange)range
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:NSArray  originalSelector:@selector(indexOfObjectIdenticalTo:inRange:) swizzledSelector:@selector(zx_avoidCrashIndexOfObjectIdenticalTo:inRange:)];

        
        //subarrayWithRange:
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:NSArray  originalSelector:@selector(subarrayWithRange:) swizzledSelector:@selector(zx_avoidCrashSubarrayWithRange:)];
        
        ///类方法
        
        //arrayByAddingObject:
        [ZXAvoidCrashRuntime exchangeInstanceMethodWithClass:NSArray originalSelector:@selector(arrayByAddingObject:) swizzledSelector:@selector(zx_avoidCrashArrayByAddingObject:)];
        
 
        
 
        
    });
}

#pragma mark- 初始化

//=================================================================
// __NSPlaceholderArray
// [NSArray alloc];
// 字面值创建：someObject= nil;NSArray *array = @[someObject];
// - (instancetype)initWithObjects:(const ObjectType _Nonnull [_Nullable])objects count:(NSUInteger)cnt
// + (instancetype)arrayWithObjects:(const ObjectType _Nonnull [_Nonnull])objects count:(NSUInteger)cnt
// + (instancetype)arrayWithObject:(ObjectType)anObject
//=================================================================

- (instancetype)zx_avoidCrashInitWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt{
    id instance = nil;
    @try {
        instance =  [self zx_avoidCrashInitWithObjects:objects count:cnt];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
        //以下是对错误数据的处理:objects不为NULL，objects内部元素是nil时会崩溃。
        if (cnt > 0 && objects != NULL)
        {
            NSInteger objsIndex = 0;
            id _Nonnull __unsafe_unretained contentsArray[cnt];
//                把为nil的数据去掉,然后初始化数组
            for (int i =0; i < cnt; i++) {
                if (objects[i] != nil) {
                    contentsArray[objsIndex] = objects[i];
                    objsIndex++;
                }
            }
            instance = [self zx_avoidCrashInitWithObjects:contentsArray count:objsIndex];
        }
        else if (cnt <= 0){
        }
        else if (objects == NULL){
        }
    } @finally {
        return instance;
    }
}

#pragma mark- 查询

#pragma mark - objectAtIndex:
//=================================================================
//                         objectAtIndex:
//=================================================================
//空元素的数组：（1）[__NSArray0 objectAtIndex:];（2）array[i]
- (id)zx___NSArray0AvoidCrashObjectAtIndex:(NSUInteger)index{
    
    id object = nil;
    @try {
        object = [self zx___NSArray0AvoidCrashObjectAtIndex:index];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
    } @finally {
        return object;
    }
}

//只有一个元素的数组：（1）[__NSSingleObjectArrayI objectAtIndex:]; （2）array[i]
- (id)zx___NSSingleObjectArrayIAvoidCrashObjectAtIndex:(NSUInteger)index{
    
    id object = nil;
    @try {
        object = [self zx___NSSingleObjectArrayIAvoidCrashObjectAtIndex:index];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
    } @finally {
        return object;
    }
}

//有多个元素的数组：[__NSArrayI objectAtIndex:]
- (id)zx___NSArrayIAvoidCrashObjectAtIndex:(NSUInteger)index{
    
    id object = nil;
    @try {
        object = [self zx___NSArrayIAvoidCrashObjectAtIndex:index];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
    } @finally {
        return object;
    }
}


#pragma mark - objectAtIndexedSubscript:

//=================================================================
//             - (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx
//=================================================================
//有多个元素的数组：-[__NSArrayI objectAtIndexedSubscript:]: index 2 beyond bounds [0 .. 1]'
- (id)zx___NSArrayIAvoidCrashObjectAtIndexedSubscript:(NSUInteger)idx
{
    id object = nil;
    @try {
        object = [self zx___NSArrayIAvoidCrashObjectAtIndexedSubscript:idx];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
    } @finally {
        return object;
    }
}


#pragma mark - objectsAtIndexes:

//=================================================================
//              - (NSArray<ObjectType> *)objectsAtIndexes:(NSIndexSet *)indexes
//=================================================================
//-[NSArray objectsAtIndexes:]: index 2 in index set beyond bounds [0 .. 0]
//-[NSArray objectsAtIndexes:]: index set cannot be nil
- (NSArray *)zx_avoidCrashObjectsAtIndexes:(NSIndexSet *)indexes
{
    NSArray *arr = nil;
    @try {
        arr = [self zx_avoidCrashObjectsAtIndexes:indexes];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
    } @finally {
        return arr;
    }
}

#pragma mark - indexOfObject:inRange:

//=================================================================
//                        indexOfObject:inRange:
//=================================================================
- (NSUInteger)zx_avoidCrashIndexOfObject:(id)anObject inRange:(NSRange)range
{
    NSUInteger index = NSNotFound;
    @try {
        index = [self zx_avoidCrashIndexOfObject:anObject inRange:range];
    } @catch (NSException *exception) {
        if(range.location>[self count]||range.length>[self count]-range.location){
            [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNSNotFound];
        }
    } @finally {
        return index;
    }
}

- (NSUInteger)zx_avoidCrashIndexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range
{
    NSUInteger index = NSNotFound;
    @try {
        index = [self zx_avoidCrashIndexOfObjectIdenticalTo:anObject inRange:range];
    } @catch (NSException *exception) {
        if(range.location>[self count]||range.length>[self count]-range.location){
            [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNSNotFound];
        }
    } @finally {
        return index;
    }
}

#pragma mark - subarrayWithRange:

//=================================================================
//                       -(NSArray *)subarrayWithRange:(NSRange)range
//=================================================================

//-[NSArray subarrayWithRange:]: range {0, 5} extends beyond bounds [0 .. 0] 
- (NSArray *)zx_avoidCrashSubarrayWithRange:(NSRange)range
{
    NSArray *arr = nil;
    @try {
        arr = [self zx_avoidCrashSubarrayWithRange:range];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_returnNil];
    } @finally {
        return arr;
    }
}



#pragma mark - 构造

#pragma mark - arrayByAddingObject:
//=================================================================
//                        arrayByAddingObject:
//=================================================================

// Trapped uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSArray arrayByAddingObject:]: object cannot be nil'
- (NSArray *)zx_avoidCrashArrayByAddingObject:(id)anObject{
    
    NSArray *instance = self;
    @try {
        instance = [self zx_avoidCrashArrayByAddingObject:anObject];
    } @catch (NSException *exception) {
        [ZXAvoidCrashReport crashReportWithException:exception avoidCrashHandleType:AvoidCrashHandleType_doNothing];
    } @finally {
        return instance;
    }
}

@end


//奔溃：
//1.+ (instancetype)arrayWithObjects:(const ObjectType _Nonnull [_Nonnull])objects count:(NSUInteger)cnt
//2.- (instancetype)initWithObjects:(const ObjectType _Nonnull [_Nullable])objects count:(NSUInteger)cnt
//3.+ (instancetype)arrayWithObject:(ObjectType)anObject

//（1）类方法
// Trapped uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[2]'
// 栈：
// 4   CoreFoundation                      0x00007fff23e170b4 -[__NSPlaceholderArray initWithObjects:count:] + 164,
// 5   CoreFoundation                      0x00007fff23e2c578 +[NSArray arrayWithObjects:count:] + 40,
//（2）.实例方法
// Trapped uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[2]'
// 栈：
//  4   CoreFoundation                      0x00007fff23e170b4 -[__NSPlaceholderArray initWithObjects:count:] + 164,


//3.- (ObjectType)objectAtIndex:(NSUInteger)index;

//3.1 空元素的数组：
//Trapped uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 3 beyond bounds for empty NSArray'
//栈：
//    1   libobjc.A.dylib                     0x00007fff512539b2 objc_exception_throw + 48,
//    2   CoreFoundation                      0x00007fff23d0595e -[__NSArray0 objectAtIndex:] + 94,


//3.2 只有一个元素的数组：
//Trapped uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 0]':索引3越界[0,0]
// 栈：
//  2   CoreFoundation                      0x00007fff23d77840 -[__NSSingleObjectArrayI getObjects:range:] + 0,

//3.3 超过一个元素的数组：
//Trapped uncaught exception 'NSRangeException', reason: '*** __boundsFail: index 3 beyond bounds [0 .. 1]'
//栈：
//    4   CoreFoundation                      0x00007fff23eaf4a6 -[__NSArrayI objectAtIndex:] + 38,
